﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Text;
using System.Reflection;

namespace NaviCar.Helpers
{
    public class Grid<T> where T : class, new()
    {
        private const string espacaoHtml = "&nbsp;";
        private IEnumerable<T> colecao;
        private IEnumerable<ColunaGrid<T>> colunas;
        public string IdGrid{ get; set;}
        public Func< T, String> ScriptSelecaoIdGrid { get; set;}
        public int QuantidadeTotal { get; set; }
        public int QuantidadeRegistrosExibidosPorPaginas { get; set; }
        public int PaginaAtual { get; set; }
        public int QuantidadePaginasExibida { get; set; }
        public bool TemPaginacao { get; set; }
        public bool TemOrdenacaoColunas { get; set; }

        private const string TEMPLATE_HEADER_SEM_TAMANHO_COM_ORD = "<th scope=\"col\" class=\"TxtTituloLista\"><input class=\"btnGrid\" type=\"submit\" value=\"{0}\" onclick=\"alterarUrlFrm(this,'{1}');\" /></th>";
        private const string TEMPLATE_HEADER_COM_TAMANHO_COM_ORD = "<th scope=\"col\" style=\"width:{0};\" class=\"TxtTituloLista\"><input class=\"btnGrid\" type=\"submit\" value=\"{1}\" onclick=\"alterarUrlFrm(this,'{2}');\" /></th>";
        private const string TEMPLATE_HEADER_SEM_TAMANHO_SEM_ORD = "<th scope=\"col\" class=\"TxtTituloLista\"><span>{0}</span></th>";
        private const string TEMPLATE_HEADER_COM_TAMANHO_SEM_ORD = "<th scope=\"col\" style=\"width:{0};\" class=\"TxtTituloLista\"><span>{0}</span></th>";

        public void Colunas(params ColunaGrid<T>[] colunas)
        {
            this.colunas = colunas;
        }

        public ColunaGrid<T> CriarColuna(string nome, string Titulo)
        {
            ColunaGrid<T> retorno = new ColunaGrid<T>();
            retorno.Nome = nome;
            retorno.Titulo = Titulo;
            

            return retorno;
        }

        public ColunaGrid<T> CriarColuna(Func<T,string> template, string Titulo)
        {
            ColunaGrid<T> retorno = new ColunaGrid<T>();
            retorno.Titulo = Titulo;
            retorno.Template = template;

            return retorno;
        }

        public Grid(string nome, IEnumerable<T> dados, int quantidadeTotal, int paginaAtual)
        {
            this.IdGrid = nome;
            this.colecao = dados;
            this.QuantidadeTotal = quantidadeTotal;
            this.PaginaAtual = paginaAtual;
            this.QuantidadePaginasExibida = 6;
            this.QuantidadeRegistrosExibidosPorPaginas = 10;
            this.TemPaginacao = true;
        }

        public Grid(string nome, IEnumerable<T> dados, int quantidadeTotal, int paginaAtual,  int quantidadeRegistrosExibidosPorPaginas)
            : this(nome, dados, quantidadeTotal, paginaAtual)
        {
            this.QuantidadeRegistrosExibidosPorPaginas = quantidadeRegistrosExibidosPorPaginas;
        }

        public HtmlString GetHtml()
        {
            StringBuilder sb = new StringBuilder();
            Type tipo = null;
            bool blnAlt = false;
            bool blnAux = false;
            string valor = string.Empty;
            Type tipocoluna = null;


            if ((colecao == null))
            {
                colecao = new List<T>();
            }
            

            if ((colunas == null || colunas.Count() == 0))
            {
                throw new ArgumentException("Nenhuma coluna definida no grid");
            }

            sb.AppendFormat("<div id=\"{0}\"  class=\"divGrid\" style=\"overflow:auto\">", IdGrid);

            sb.Append("<table border=\"0\" align=\"left\" cellpadding=\"0\" cellspacing=\"0\" class=\"bordaCinzaClara\">");
            sb.Append("<thead>");
            sb.Append("<tr>");

            int quantidadeRenderizados = 0;

            if ((colecao != null))
            {
                foreach (T item in colecao)
                {
                    tipo = item.GetType();
                }

                //colecao.GetEnumerator().Reset();

                string auxTitulo = string.Empty;


                foreach (ColunaGrid<T> item in colunas)
                {
                    auxTitulo = string.IsNullOrEmpty(item.Titulo) ? "&nbsp;" : item.Titulo;

                    if ((!blnAux))
                    {
                        if ((ScriptSelecaoIdGrid != null))
                        {
                            sb.AppendFormat("<th scope=\"col\" style=\"width:15px;\" class=\"TxtTituloLista\">&nbsp;</th>");
                        }

                    }
                    else
                    {
                        if (!TemOrdenacaoColunas || item.Template != null)
                        {

                            if ((string.IsNullOrEmpty(item.Tamanho)))
                            {
                                sb.Append(string.Format("<th scope=\"col\" class=\"TxtTituloLista\">{0}</th>", auxTitulo, item.Nome));
                            }
                            else
                            {
                                sb.Append(string.Format("<th scope=\"col\" style=\"width:{0};\" class=\"TxtTituloLista\">{1}</th>", item.Tamanho, auxTitulo, item.Nome));
                            }
                        }
                        else
                        {
                            if ((string.IsNullOrEmpty(item.Tamanho)))
                            {
                                sb.Append(string.Format(TEMPLATE_HEADER_SEM_TAMANHO_COM_ORD, auxTitulo, item.Nome));
                            }
                            else
                            {
                                sb.Append(string.Format(TEMPLATE_HEADER_COM_TAMANHO_COM_ORD, item.Tamanho, auxTitulo, item.Nome));
                            }
                        }
                    }

                    blnAux = true;
                }

                sb.Append("</tr>");
                sb.Append("</thead>");

                
                foreach (T entidade in colecao)
                {
                    quantidadeRenderizados += 1;
                    blnAux = false;
                    
                    int aux = 0;

                    foreach (ColunaGrid<T> colGrd in this.colunas)
                    {
                        tipocoluna = colGrd.GetType();


                        if (colGrd.Template != null)
                        {
                            valor = colGrd.Template(entidade);
                        }
                        else if(colGrd.Formato != null && !string.IsNullOrEmpty(colGrd.Nome))
                        {
                            valor = colGrd.Formato(entidade);
                        }
                        else if (!String.IsNullOrEmpty(colGrd.Nome))
                        {
                            valor = RecuperarValorAtributoColunaGrid(colGrd.Nome, entidade, colGrd.Dicionario);
                        }
                        else
                        {
                            throw new ArgumentException("Faltam parâmetros para renderizar o Grid.");
                        }

                        if ((valor == null))
                        {
                            valor = espacaoHtml;
                        }


                        if ((!blnAux))
                        {
                            sb.AppendFormat("<tr indice=\"{0}\">", valor);

                            if ((ScriptSelecaoIdGrid != null))
                            {
                                sb.AppendFormat("<td class=\"TxtListaSel\"><a href=\"{0}\"><img class=\"imgFechar\" src=\"{1}\"/></a></td>", ScriptSelecaoIdGrid(entidade), "../Styles/images/editar.png");
                            }


                        }
                        else
                        {
                            if ((!string.IsNullOrEmpty(colGrd.Tamanho)))
                            {
                                sb.AppendFormat("<td class=\"TxtLista\" style=\"width:{0}\">{1}</td>", colGrd.Tamanho, valor);
                            }
                            else
                            {
                                sb.AppendFormat("<td class=\"TxtLista\">{0}</td>", valor);
                            }
                        }

                        blnAux = true;

                        aux = aux + 1;
                    }





                    blnAlt = !blnAlt;

                    if (quantidadeRenderizados == this.QuantidadeRegistrosExibidosPorPaginas) { break; }

                }

                sb.Append("</tr>");
            }
            


            if ((quantidadeRenderizados == 0))
            {
                sb.AppendFormat("<tr id=\"divRegNaoEnc\"> <td colspan='{0}'>Nenhum registro encontrado.</td></tr>", colunas.Count());
            }

            if (this.TemPaginacao)
            {
                sb.Append(this.Paginador());
            }

            sb.Append("</table>");
            sb.AppendFormat("<input type=\"hidden\" id=\"{0}\" class=\"hnPaginacao\" name=\"hdpgl\" />",this.GerarNomeHidden());
            sb.AppendFormat("</div>");

            return MvcHtmlString.Create(sb.ToString());

        }

        private string GerarNomeHidden()
        {
            return string.Format("hgid{0}",this.IdGrid);
        }

        
        private string RenderizarLinkPagina(int pagina, int paginaAtual, string texto)
        {
	        if ((pagina == paginaAtual)) {
		        return string.Format("<span>{0}</span>", pagina);

	        } else {
                if (string.IsNullOrEmpty(texto))
                {
                    return string.Format("<input type=\"submit\" class=\"btnGrid\" value=\"{1}\" onclick=\"$('#{0}').val('{1}');return true;\" class=\"btPg\">", this.GerarNomeHidden(), pagina);
                }
                else
                {
                    return string.Format("<input type=\"submit\" class=\"btnGrid\" value=\"{2}\" onclick=\"$('#{0}').val('{1}');return true;\" class=\"btPg\">", this.GerarNomeHidden(), pagina, texto);
                }
                
	        }
        }

        public string Paginador()
        {
	        int i = 0;
	        int j = 0;
	        int qtdPaginas = 0;
	        int aux = 0;
	        int pgAtual = 0;

	      
	        qtdPaginas = Convert.ToInt32(QuantidadeTotal / QuantidadeRegistrosExibidosPorPaginas);

	        int primeiroItem = 0;
	        int NumeracaoPgExibas = 0;

	        aux = Convert.ToInt32(qtdPaginas / 2);
	        StringBuilder sb = new StringBuilder();


	        if ((QuantidadeTotal % QuantidadeRegistrosExibidosPorPaginas > 0)) {
		        qtdPaginas += 1;
	        }

	        if (PaginaAtual > qtdPaginas) {
		        pgAtual = qtdPaginas;
	        } else {
		        pgAtual = PaginaAtual;
	        }

	        //---------------números para paginação---------------------
	        primeiroItem = pgAtual - (QuantidadePaginasExibida / 2);

	        if ((primeiroItem < 1))
		        primeiroItem = 1;

	        NumeracaoPgExibas = primeiroItem + QuantidadePaginasExibida;

	        if ((NumeracaoPgExibas > qtdPaginas))
		        NumeracaoPgExibas = qtdPaginas;
	        //---------------------------------------------------------

            sb.AppendFormat("<tfoot><tr><td colspan=\"{0}\">", this.colunas.Count());
            sb.Append(RenderizarLinkPagina(1, 0,"<<"));           

	        for (i = primeiroItem; i <= NumeracaoPgExibas; i++) {
                sb.AppendFormat(RenderizarLinkPagina(i,pgAtual,string.Empty));
	        }


            sb.Append(RenderizarLinkPagina(qtdPaginas, 0,">>"));
            sb.Append("</td></tr></tfoot>");

	        return sb.ToString();

        }

        /// <summary>
        /// Recupera o valor da propriedade da classe
        /// </summary>
        /// <param name="campo">Nome da propriedade</param>
        /// <param name="entidade">Entidade de dados</param>
        /// <param name="dicionario">Dicionario para tradução de valores</param>
        /// <returns>Valor para exibição no grid</returns>
        private string RecuperarValorAtributoColunaGrid(string campo, object entidade, IDictionary<object, string> dicionario)
        {
	        object auxRetorno = RecuperarValorPropriedade(campo, entidade);
	        string retorno = null;

	        if ((dicionario != null && auxRetorno != null)) {
		        //retorno = RecuperarValorDicionario(auxRetorno, dicionario);
	        } else {
		        retorno = ValidarValor(auxRetorno);
	        }

	        return retorno;
        }

        /// <summary>
        /// Recupera o valor de uma propridade do objeto a partir de uma representação em string separada por .
        /// </summary>
        /// <param name="campo">String separada por .</param>
        /// <param name="obj">Objeto principal</param>
        private object RecuperarValorPropriedade(string campo, object obj)
        {
	        string[] auxCampo = campo.Split('.');
	        Type tipo = obj.GetType();
	        PropertyInfo prop = null;
	        object objAux = obj;
	        object valor = null;



	        foreach (string item in auxCampo) {
		        prop = tipo.GetProperty(item);

		        if ((objAux != null)) {
			        try {
				        valor = prop.GetValue(objAux, null);
			        } catch (Exception ex) {
				        valor = "";
			        }

		        } else {
			        return null;
		        }



		        objAux = valor;

		        if ((valor != null))
			        tipo = objAux.GetType();
	        }

	        return valor;

        }

        private string RecuperarValorDicionario(object valor, Dictionary<object, string> dicionario)
        {
	        if (valor != null)
		        return string.Empty;

	        if ((dicionario.Keys.Contains(valor))) {
		        return dicionario[valor];
	        } else {
		        //return valor;
                return null;
	        }
        }


        private string ValidarValor(object valor)
        {
	        string retorno = string.Empty;

	        if ((valor == null)) {
		        valor = string.Empty;
	        }

	        valor.GetType();



	        if ((valor is System.DateTime)) {
		        retorno = ((DateTime)valor).ToString("dd/MM/yyyy");

	        } else {
		        if ((valor.ToString().Length > 150)) {
			        retorno = string.Concat(valor.ToString().Substring(0, 150), " ...");
		        //Return valor
		        } else {
			        retorno = valor.ToString();
		        }


	        }

	        if ((string.IsNullOrEmpty(retorno))) {
		        retorno = espacaoHtml;
	        } else {
		        retorno = HttpUtility.HtmlEncode(retorno);
	        }




	        return retorno;
        }

    }
}